﻿using NUnit.Framework;
using System;

namespace RenewalProjects.Libraries.SharedCode.Tests
{
	[TestFixture]
	public class ExceptionUtilitiesFixture
	{
		[Test]
		public void Single_exception_formatting_without_indentation_and_stacktrace_test()
		{
			string result = ExceptionUtilities.FormatException(new Exception("Just the exception"), 0);
			string[] lines = result.Split(Environment.NewLine.ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
			Assert.AreEqual(1, lines.Length);
			StringAssert.AreEqualIgnoringCase("[\"Just the exception\" - System.Exception]", lines[0]);
		}

		[Test]
		public void Single_exception_formatting_without_indentation_test()
		{
			string result = ExceptionUtilities.FormatException(ExceptionWithStacktrace("Sample exception"), 0);
			string[] lines = result.Split(Environment.NewLine.ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
			Assert.AreEqual(2, lines.Length);
			StringAssert.AreEqualIgnoringCase("[\"Sample exception\" - System.Exception]", lines[0]);
			StringAssert.StartsWith(
				"   at RenewalProjects.Libraries.SharedCode.Tests.ExceptionUtilitiesFixture.ExceptionWithStacktrace(String exceptionMessage, Exception innerException)",
				lines[1]);
		}

		[Test]
		public void Single_exception_formatting_with_one_indentation_test()
		{
			string result = ExceptionUtilities.FormatException(ExceptionWithStacktrace("Sample exception"), 1);
			string[] lines = result.Split(Environment.NewLine.ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
			Assert.AreEqual(2, lines.Length);
			StringAssert.AreEqualIgnoringCase("\t[\"Sample exception\" - System.Exception]", lines[0]);
			StringAssert.StartsWith(
				"\t   at RenewalProjects.Libraries.SharedCode.Tests.ExceptionUtilitiesFixture.ExceptionWithStacktrace(String exceptionMessage, Exception innerException)",
				lines[1]);
		}

		[Test]
		public void Single_exception_formatting_with_two_indentation_test()
		{
			string result = ExceptionUtilities.FormatException(ExceptionWithStacktrace("Sample exception"), 2);
			string[] lines = result.Split(Environment.NewLine.ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
			Assert.AreEqual(2, lines.Length);
			StringAssert.AreEqualIgnoringCase("\t\t[\"Sample exception\" - System.Exception]", lines[0]);
			StringAssert.StartsWith(
				"\t\t   at RenewalProjects.Libraries.SharedCode.Tests.ExceptionUtilitiesFixture.ExceptionWithStacktrace(String exceptionMessage, Exception innerException)",
				lines[1]);
		}

		[Test]
		public void Single_exception_formatting_with_one_indentation_and_two_callstacks_test()
		{
			string result = ExceptionUtilities.FormatException(DeeperExceptionWithStacktrace("Sample exception"), 1);
			string[] lines = result.Split(Environment.NewLine.ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
			Assert.AreEqual(3, lines.Length);
			StringAssert.AreEqualIgnoringCase("\t[\"Sample exception\" - System.Exception]", lines[0]);
			StringAssert.StartsWith(
				"\t   at RenewalProjects.Libraries.SharedCode.Tests.ExceptionUtilitiesFixture.ThrowException(String exceptionMessage, Exception innerException)",
				lines[1]);
			StringAssert.StartsWith(
				"\t   at RenewalProjects.Libraries.SharedCode.Tests.ExceptionUtilitiesFixture.DeeperExceptionWithStacktrace(String exceptionMessage, Exception innerException)",
				lines[2]);
		}

		[Test]
		public void Double_exception_formatting_with_two_indentation_and_lower_indentation_and_two_callstacks_test()
		{
			string result =
			        ExceptionUtilities.FormatExceptionDepth(DeeperExceptionWithStacktrace("Sample exception",
						DeeperExceptionWithStacktrace("Inner exception")), 2, true);
			string[] lines = result.Split(Environment.NewLine.ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
			Assert.AreEqual(6, lines.Length);
			StringAssert.AreEqualIgnoringCase("\t\t[\"Sample exception\" - System.Exception]", lines[0]);
			StringAssert.StartsWith(
				"\t\t   at RenewalProjects.Libraries.SharedCode.Tests.ExceptionUtilitiesFixture.ThrowException(String exceptionMessage, Exception innerException)",
				lines[1]);
			StringAssert.StartsWith(
				"\t\t   at RenewalProjects.Libraries.SharedCode.Tests.ExceptionUtilitiesFixture.DeeperExceptionWithStacktrace(String exceptionMessage, Exception innerException)",
				lines[2]);
			StringAssert.AreEqualIgnoringCase("\t\t\t[\"Inner exception\" - System.Exception]", lines[3]);
			StringAssert.StartsWith(
				"\t\t\t   at RenewalProjects.Libraries.SharedCode.Tests.ExceptionUtilitiesFixture.ThrowException(String exceptionMessage, Exception innerException)",
				lines[4]);
			StringAssert.StartsWith(
				"\t\t\t   at RenewalProjects.Libraries.SharedCode.Tests.ExceptionUtilitiesFixture.DeeperExceptionWithStacktrace(String exceptionMessage, Exception innerException)",
				lines[5]);
		}

		[Test]
		public void Double_exception_formatting_with_two_indentation_and__no_lower_indentation_and_two_callstacks_test()
		{
			string result =
			        ExceptionUtilities.FormatExceptionDepth(DeeperExceptionWithStacktrace("Sample exception",
						DeeperExceptionWithStacktrace("Inner exception")), 2, false);
			string[] lines = result.Split(Environment.NewLine.ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
			Assert.AreEqual(6, lines.Length);
			StringAssert.AreEqualIgnoringCase("\t\t[\"Sample exception\" - System.Exception]", lines[0]);
			StringAssert.StartsWith(
				"\t\t   at RenewalProjects.Libraries.SharedCode.Tests.ExceptionUtilitiesFixture.ThrowException(String exceptionMessage, Exception innerException)",
				lines[1]);
			StringAssert.StartsWith(
				"\t\t   at RenewalProjects.Libraries.SharedCode.Tests.ExceptionUtilitiesFixture.DeeperExceptionWithStacktrace(String exceptionMessage, Exception innerException)",
				lines[2]);
			StringAssert.AreEqualIgnoringCase("\t\t[\"Inner exception\" - System.Exception]", lines[3]);
			StringAssert.StartsWith(
				"\t\t   at RenewalProjects.Libraries.SharedCode.Tests.ExceptionUtilitiesFixture.ThrowException(String exceptionMessage, Exception innerException)",
				lines[4]);
			StringAssert.StartsWith(
				"\t\t   at RenewalProjects.Libraries.SharedCode.Tests.ExceptionUtilitiesFixture.DeeperExceptionWithStacktrace(String exceptionMessage, Exception innerException)",
				lines[5]);
		}

		private static Exception DeeperExceptionWithStacktrace(string exceptionMessage, Exception innerException = null)
		{
			try
			{
				ThrowException(exceptionMessage, innerException);
			}
			catch(Exception ex)
			{
				return ex;
			}

			return null;
		}

		private static void ThrowException(string exceptionMessage, Exception innerException = null)
		{
			throw new Exception(exceptionMessage, innerException);
		}

		private static Exception ExceptionWithStacktrace(string exceptionMessage, Exception innerException = null)
		{
			try
			{
				throw new Exception(exceptionMessage, innerException);
			}
			catch(Exception ex)
			{
				return ex;
			}
		}
	}
}